<?php

/**
*
 * @package Pico
 * @subpackage mcb_TableOfContent
 * @version 0.3.1
 * @author mcbSolutions.at <dev@mcbsolutions.at>
 * @author notabug.org/ohnonot
 *
 * ## Changelog
 *
 *  + 2016-11-17 Upgrade to AbstractPicoPlugin for Pico 1.0
 *  + 2016-11-19
 *     + Removed some parameters
 *     + Added the test page
 *  + 2019-> Much hacked to be included in my (ohnonot) tagblog theme
 * 
*/
class TableOfContent extends AbstractPicoPlugin {

   // only act if this var is set to "true"
   private $yeah       = "false";

   // default settings
   private $depth       = 3;
   private $min_headers = 3;
   private $top_txt     = 'Top';
   private $caption     = "Table of contents";
   private $template    = "all"; // config to valid twig template to only act on that template -  defaults to all templates.

   // internal
   private $toc = '';
   private $xpQuery;
	private $content;

   public function onConfigLoaded(&$config)
   {
      if(isset($config['TableOfContent']['depth'      ])) $this->depth       = &$config['TableOfContent']['depth'];
      if(isset($config['TableOfContent']['min_headers'])) $this->min_headers = &$config['TableOfContent']['min_headers'];
      if(isset($config['TableOfContent']['top_txt'    ])) $this->top_txt     = &$config['TableOfContent']['top_txt'];
      if(isset($config['TableOfContent']['caption'    ])) $this->caption     = &$config['TableOfContent']['caption'];
      if(isset($config['TableOfContent']['template'   ])) $this->template    = &$config['TableOfContent']['template'];

      for ($i=1; $i <= $this->depth; $i++) {
         $this->xpQuery[] = "//h$i";
      }
      $this->xpQuery = join("|", $this->xpQuery);
   }
   public function onMetaParsed(array  $meta)
   {
   	  if(isset($meta['toc_disabled']) && $meta['toc_disabled'] === TRUE) return;
   	  if(isset($meta['toc_enabled']) && $meta['toc_enabled'] === FALSE) return;
      if($meta['template'] === $this->template || $this->template === "all") $this->yeah = "true";
   }

   private function makeToc(&$content)
   {
      // if there are any headings, put them in $headers
      if(preg_match_all('/<h[1-'.$this->depth.']{1,1}[^>]*>.*?<\/h[1-'.$this->depth.']>/s',$content,$headers) === false)
         return "";

      //create the toc
      $this->headers = $headers;
      $heads = implode("\n",$headers[0]);

      // removes the toc-nav link included in each header
      $heads = str_replace('<a href="#" class="toc-nav">'.$this->top_txt.'</a>','',$heads);
      // removes links, leaving link text stackoverflow.com/a/3830750
      $heads = preg_replace('#<a.*?>(.*?)</a>#i','\1',$heads);
      // builds the list of links
      $heads = preg_replace('/<h([1-'.$this->depth.']).+?id="?/','<li class="toc$1"><a href="#',$heads);
      $heads = preg_replace('/<\/h[1-'.$this->depth.']>/','</a></li>',$heads);

      $cap = $this->caption =='' ? "" :  '<p id="toc-header">'.$this->caption.'</p>';

      return '<div id="toc">'.$cap.'<ul>'.$heads.'</ul></div>';
   }

	public function onContentParsed(&$content)
   {
      // only continue if we want TOC for this page
      if($this->yeah != "true") return;

      if(trim($content)=="")
        return;
      $dom = new DOMDocument('1.0', 'utf-8');
    $xml_utf='<?xml encoding="utf-8" ?>';
    $dom->loadHTML($xml_utf.$content,LIBXML_HTML_NOIMPLIED+LIBXML_NOERROR+LIBXML_HTML_NODEFDTD);

      $xp = new DOMXPath($dom);
      $nodes =$xp->query($this->xpQuery);

      if($nodes->length < $this->min_headers)
         return;

      // add missing id's to the h tags
      foreach($nodes as $i => $sort)
      {
          if (isset($sort->tagName) && $sort->tagName !== '')
          {
             if($sort->getAttribute('id') === "")
             {
                $text = preg_replace('~[^\\pL0-9_]+~u', '-', $sort->nodeValue);
                $text = trim($text,'-');
                $sort->setAttribute('id',strtolower($text));

                $a = $dom->createElement('a', $this->top_txt);
                $a->setAttribute('href', '#');
                $a->setAttribute('class', 'toc-nav');
                $sort->appendChild($a);
             }
          }
      }
      $content = $dom->saveHTML();
      // remove the xml_utf tag we added at loadHTML($xml_utf.$content...
      $len = strlen($xml_utf); if(substr($content,0,$len) === $xml_utf) $content = substr($content,$len);

      $this->toc = $this->makeToc($content);
   }

   public function onPageRendering(&$twig, &$twigVariables, &$templateName)
   {
      if($this->yeah != "true") return;

      $twigVariables['tableofcontent'] = $this->toc;
   }
}
